gdk: x11: Fill GdkMonitor manufacturer with PNP id from EDID
authorPriit Laes <priit.laes@paf.com>
Tue, 6 Aug 2019 06:16:01 +0000 (09:16 +0300)
committerPriit Laes <priit.laes@paf.com>
Tue, 6 Aug 2019 06:16:01 +0000 (09:16 +0300)
Previously, the manufacturer property of the GdkMonitor was NULL,
and having at least PNP id at GdkMonitor.manufacturer makes it
possible to distinguish between different monitors programmatically.

gdk/gdkmonitor.c
gdk/x11/gdkscreen-x11.c

index 2d27c29972254bef56bc3b3fdbe6e8ca4f4db15a..37e2c872eb0b7c5953c675ab1d56f12550e5fffe 100644 (file)
@@ -401,7 +401,12 @@ gdk_monitor_get_connector (GdkMonitor *monitor)
  * gdk_monitor_get_manufacturer:
  * @monitor: a #GdkMonitor
  *
- * Gets the name of the monitor's manufacturer, if available.
+ * Gets the name or PNP ID of the monitor's manufacturer, if available.
+ *
+ * Note that this value might also vary depending on actual
+ * display backend.
+ *
+ * PNP ID registry is located at https://uefi.org/pnp_id_list
  *
  * Returns: (transfer none) (nullable): the name of the manufacturer, or %NULL
  */
index cda654f04ed57ab61a03dd7cabda4a61b8263e89..ffba0708f7ab28ae11707e56d5edc011eb5e2fd6 100644 (file)
@@ -354,6 +354,7 @@ init_randr15 (GdkX11Screen *x11_screen, gboolean *changed)
       GdkRectangle geometry;
       GdkRectangle newgeo;
       char *name;
+      char *manufacturer = NULL;
       int refresh_rate = 0;
 
       gdk_x11_display_error_trap_push (display);
@@ -405,6 +406,50 @@ init_randr15 (GdkX11Screen *x11_screen, gboolean *changed)
           g_ptr_array_add (x11_display->monitors, monitor);
         }
 
+      /* Fetch minimal manufacturer information (PNP ID) from EDID */
+      {
+        #define EDID_LENGTH 128
+        Atom actual_type, edid_atom;
+        char tmp[3];
+        int actual_format;
+        unsigned char *prop;
+        unsigned long nbytes, bytes_left;
+        Display *disp = GDK_DISPLAY_XDISPLAY (x11_display);
+
+        edid_atom = XInternAtom (disp, RR_PROPERTY_RANDR_EDID, FALSE);
+
+        XRRGetOutputProperty (disp, output,
+                              edid_atom,
+                              0,
+                              EDID_LENGTH,
+                              FALSE,
+                              FALSE,
+                              AnyPropertyType,
+                              &actual_type,
+                              &actual_format,
+                              &nbytes,
+                              &bytes_left,
+                              &prop);
+
+        // Check partial EDID header (whole header: 00 ff ff ff ff ff ff 00)
+        if (nbytes >= EDID_LENGTH && prop[0] == 0x00 && prop[1] == 0xff)
+          {
+            /* decode the Vendor ID from three 5 bit words packed into 2 bytes
+             * /--08--\/--09--\
+             * 7654321076543210
+             * |\---/\---/\---/
+             * R  C1   C2   C3 */
+            tmp[0] = 'A' + ((prop[8] & 0x7c) / 4) - 1;
+            tmp[1] = 'A' + ((prop[8] & 0x3) * 8) + ((prop[9] & 0xe0) / 32) - 1;
+            tmp[2] = 'A' + (prop[9] & 0x1f) - 1;
+
+            manufacturer = g_strndup (tmp, sizeof (tmp));
+          }
+
+        XFree(prop);
+        #undef EDID_LENGTH
+      }
+
       gdk_monitor_get_geometry (GDK_MONITOR (monitor), &geometry);
       name = g_strndup (output_info->name, output_info->nameLen);
 
@@ -433,6 +478,8 @@ init_randr15 (GdkX11Screen *x11_screen, gboolean *changed)
       gdk_monitor_set_scale_factor (GDK_MONITOR (monitor), x11_screen->surface_scale);
       gdk_monitor_set_model (GDK_MONITOR (monitor), name);
       gdk_monitor_set_connector (GDK_MONITOR (monitor), name);
+      gdk_monitor_set_manufacturer (GDK_MONITOR (monitor), manufacturer);
+      g_free (manufacturer);
       g_free (name);
 
       if (rr_monitors[i].primary)